﻿using System;
using System.Collections.Generic;
using System.Data;
using MySql.Data.MySqlClient;
using l1cs.server.utils;
using l1cs.server.datatables;

namespace l1cs.server.server.datatables
{
    public class MapsTable
    {
        private class MapData
        {
            public int startX = 0;
            public int endX = 0;
            public int startY = 0;
            public int endY = 0;
            public double monster_amount = 1;
            public double dropRate = 1;
            public bool isUnderwater = false;
            public bool markable = false;
            public bool teleportable = false;
            public bool escapable = false;
            public bool isUseResurrection = false;
            public bool isUsePainwand = false;
            public bool isEnabledDeathPenalty = false;
            public bool isTakePets = false;
            public bool isRecallPets = false;
            public bool isUsableItem = false;
            public bool isUsableSkill = false;
        }

        private static Logger _log = Logger.getLogger( typeof( MapsTable ).FullName );

        private static MapsTable _instance;

        /// <summary>
        /// KeyにマップID、Valueにテレポート可否フラグが格納されるHashMap
        /// </summary>
        private Dictionary<int, MapData> _maps = new Dictionary<int, MapData>();

        /// <summary>
        /// 新しくMapsTableオブジェクトを生成し、マップのテレポート可否フラグを読み込む。
        /// </summary>
        private MapsTable()
        {/*TTOK*/
            String sqlstr = "SELECT * FROM mapids";
            using ( MySqlWrapper wrapper = new MySqlWrapper() )
            {
                foreach ( DataRow item in wrapper.GetDataTable( sqlstr ).Rows )
                {
                    MapData data = new MapData();
                    int mapId = SqlUtils.toInt( item["mapid"] );
                    data.startX = SqlUtils.toInt( item["startX"] );
                    data.endX = SqlUtils.toInt( item["endX"] );
                    data.startY = SqlUtils.toInt( item["startY"] );
                    data.endY = SqlUtils.toInt( item["endY"] );
                    data.monster_amount = Convert.ToDouble( item["monster_amount"] );
                    data.dropRate = Convert.ToDouble( item["drop_rate"] );
                    data.isUnderwater = Convert.ToBoolean( item["underwater"] );
                    data.markable = Convert.ToBoolean( item["markable"] );
                    data.teleportable = Convert.ToBoolean( item["teleportable"] );
                    data.escapable = Convert.ToBoolean( item["escapable"] );
                    data.isUseResurrection = Convert.ToBoolean( item["resurrection"] );
                    data.isUsePainwand = Convert.ToBoolean( item["painwand"] );
                    data.isEnabledDeathPenalty = Convert.ToBoolean( item["penalty"] );
                    data.isTakePets = Convert.ToBoolean( item["take_pets"] );
                    data.isRecallPets = Convert.ToBoolean( item["recall_pets"] );
                    data.isUsableItem = Convert.ToBoolean( item["usable_item"] );
                    data.isUsableSkill = Convert.ToBoolean( item["usable_skill"] );

                    _maps[mapId] = data;
                }
            }
            _log.config( "Maps " + _maps.Count );
        }

        public static MapsTable getInstance()
        {
            if ( _instance == null )
            {
                _instance = new MapsTable();
            }
            return _instance;
        }

        /// <summary>
        /// マップがのX開始座標を返す。
        /// </summary>
        /// <param name="mapId">調べるマップのマップID</param>
        /// <returns>X開始座標</returns>
        public int getStartX( int mapId )
        {
            MapData map;
            _maps.TryGetValue( mapId, out map );
            if ( map == null )
            {
                return 0;
            }
            return _maps[mapId].startX;
        }

        /// <summary>
        /// マップがのX終了座標を返す。
        /// </summary>
        /// <param name="mapId">調べるマップのマップID</param>
        /// <returns>X終了座標</returns>
        public int getEndX( int mapId )
        {
            MapData map;
            _maps.TryGetValue( mapId, out map );
            if ( map == null )
            {
                return 0;
            }
            return _maps[mapId].endX;
        }

        /// <summary>
        /// マップがのY開始座標を返す。
        /// </summary>
        /// <param name="mapId">調べるマップのマップID</param>
        /// <returns>Y開始座標</returns>
        public int getStartY( int mapId )
        {
            MapData map;
            _maps.TryGetValue( mapId, out map );
            if ( map == null )
            {
                return 0;
            }
            return _maps[mapId].startY;
        }

        /// <summary>
        /// マップがのY終了座標を返す。
        /// </summary>
        /// <param name="mapId">調べるマップのマップID</param>
        /// <returns>Y終了座標</returns>
        public int getEndY( int mapId )
        {
            MapData map;
            _maps.TryGetValue( mapId, out map );
            if ( map == null )
            {
                return 0;
            }
            return _maps[mapId].endY;
        }

        /// <summary>
        /// マップのモンスター量倍率を返す。
        /// </summary>
        /// <param name="mapId">調べるマップのマップID</param>
        /// <returns>モンスター量の倍率</returns>
        public double getMonsterAmount( int mapId )
        {/*TTOK*/
            MapData map;
            _maps.TryGetValue( mapId, out map );
            if ( map == null )
            {
                return 0;
            }
            return map.monster_amount;
        }

        /// <summary>
        /// マップのドロップ倍率を返す。
        /// </summary>
        /// <param name="mapId">調べるマップのマップID</param>
        /// <returns>ドロップ倍率</returns>
        public double getDropRate( int mapId )
        {/*TTOK*/
            MapData map;
            _maps.TryGetValue( mapId, out map );
            if ( map == null )
            {
                return 0;
            }
            return map.dropRate;
        }

        /// <summary>
        /// マップが、水中であるかを返す。
        /// </summary>
        /// <param name="mapId">調べるマップのマップID</param>
        /// <returns>水中であればtrue</returns>
        public bool isUnderwater( int mapId )
        {/*TTOK*/
            MapData map;
            _maps.TryGetValue( mapId, out map );
            if ( map == null )
            {
                return false;
            }
            return _maps[mapId].isUnderwater;
        }

        /// <summary>
        /// マップが、ブックマーク可能であるかを返す。
        /// </summary>
        /// <param name="mapId">調べるマップのマップID</param>
        /// <returns>ブックマーク可能であればtrue</returns>
        public bool isMarkable( int mapId )
        {/*TTOK*/
            MapData map;
            _maps.TryGetValue( mapId, out map );
            if ( map == null )
            {
                return false;
            }
            return _maps[mapId].markable;
        }

        /// <summary>
        /// マップが、ランダムテレポート可能であるかを返す。
        /// </summary>
        /// <param name="mapId">調べるマップのマップID</param>
        /// <returns>可能であればtrue</returns>
        public bool isTeleportable( int mapId )
        {/*TTOK*/
            MapData map;
            _maps.TryGetValue( mapId, out map );
            if ( map == null )
            {
                return false;
            }
            return _maps[mapId].teleportable;
        }

        /// <summary>
        /// マップが、MAPを超えたテレポート可能であるかを返す。
        /// </summary>
        /// <param name="mapId">調べるマップのマップID</param>
        /// <returns>可能であればtrue</returns>
        public bool isEscapable( int mapId )
        {/*TTOK*/
            MapData map;
            _maps.TryGetValue( mapId, out map );
            if ( map == null )
            {
                return false;
            }
            return _maps[mapId].escapable;
        }

        /// <summary>
        /// マップが、復活可能であるかを返す。
        /// </summary>
        /// <param name="mapId">調べるマップのマップID</param>
        /// <returns>復活可能であればtrue</returns>
        public bool isUseResurrection( int mapId )
        {/*TTOK*/
            MapData map;
            _maps.TryGetValue( mapId, out map );
            if ( map == null )
            {
                return false;
            }
            return _maps[mapId].isUseResurrection;
        }

        /// <summary>
        /// マップが、パインワンド使用可能であるかを返す。
        /// </summary>
        /// <param name="mapId">調べるマップのマップID</param>
        /// <returns>パインワンド使用可能であればtrue</returns>
        public bool isUsePainwand( int mapId )
        {/*TTOK*/
            MapData map;
            _maps.TryGetValue( mapId, out map );
            if ( map == null )
            {
                return false;
            }
            return _maps[mapId].isUsePainwand;
        }

        /// <summary>
        /// マップが、デスペナルティがあるかを返す。
        /// </summary>
        /// <param name="mapId">調べるマップのマップID</param>
        /// <returns>デスペナルティであればtrue</returns>
        public bool isEnabledDeathPenalty( int mapId )
        {/*TTOK*/
            MapData map;
            _maps.TryGetValue( mapId, out map );
            if ( map == null )
            {
                return false;
            }
            return _maps[mapId].isEnabledDeathPenalty;
        }

        /// <summary>
        /// マップが、ペット・サモンを連れて行けるかを返す。
        /// </summary>
        /// <param name="mapId">調べるマップのマップID</param>
        /// <returns>ペット・サモンを連れて行けるならばtrue</returns>
        public bool isTakePets( int mapId )
        {/*TTOK*/
            MapData map;
            _maps.TryGetValue( mapId, out map );
            if ( map == null )
            {
                return false;
            }
            return _maps[mapId].isTakePets;
        }

        /// <summary>
        /// マップが、ペット・サモンを呼び出せるかを返す。
        /// </summary>
        /// <param name="mapId">調べるマップのマップID</param>
        /// <returns>ペット・サモンを呼び出せるならばtrue</returns>
        public bool isRecallPets( int mapId )
        {/*TTOK*/
            MapData map;
            _maps.TryGetValue( mapId, out map );
            if ( map == null )
            {
                return false;
            }
            return _maps[mapId].isRecallPets;
        }

        /// <summary>
        /// マップが、アイテムを使用できるかを返す。
        /// </summary>
        /// <param name="mapId">調べるマップのマップID</param>
        /// <returns>アイテムを使用できるならばtrue</returns>
        public bool isUsableItem( int mapId )
        {/*TTOK*/
            MapData map;
            _maps.TryGetValue( mapId, out map );
            if ( map == null )
            {
                return false;
            }
            return _maps[mapId].isUsableItem;
        }

        /// <summary>
        /// マップが、スキルを使用できるかを返す。
        /// </summary>
        /// <param name="mapId">調べるマップのマップID</param>
        /// <returns>スキルを使用できるならばtrue</returns>
        public bool isUsableSkill( int mapId )
        {/*TTOK*/
            MapData map;
            _maps.TryGetValue( mapId, out map );
            if ( map == null )
            {
                return false;
            }
            return _maps[mapId].isUsableSkill;
        }
    }
}
